<!doctype html>
<html>
	<head>
		<title>Quantum Circuit Simulator Example</title>
	</head>

	<body>
		<h5>Examples</h5>
		<button type="button" id="bell">Bell state</button>
		<button type="button" id="toffoli">Toffoli gate</button>
		<button type="button" id="qft2">2 qubit QFT</button>
		<button type="button" id="qft4">4 qubit QFT</button>
		<button type="button" id="adder">4-bit Adder</button>
		<button type="button" id="bigadder">8-bit Adder</button>
		<br />
		<br />
		<div>
			<input type="checkbox" id="random-input">
			<label for="random-input">Random input</label>
		</div>
		<br />
		<br />
		<a id="quirk" style="display: none" href="#" target="_blank">Open Quirk</a>
		<br />
		<div id="drawing"></div>
		<pre><code id="output"></code></pre>

		<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>

		<script src="../../dist/quantum-circuit.min.js"></script>

		<script>
			var randomInput = false;

			let circuit = new QuantumCircuit();

			function bell() {
				clearLog();

				circuit.init();

				circuit.addGate("h",  0, 0);
				circuit.addGate("cx", 1, [0, 1]);

				let input = randomizeInput();

				circuit.run(input);

				LogOutput();

				ShowCircuit();
			}

			function qft2() {
				clearLog();

				circuit.init();

				circuit.addGate("h",    0, 0);
				circuit.addGate("cr2",  1, [1, 0]);
				circuit.addGate("h",    2, 1);
				circuit.addGate("swap", 3, [0, 1]);

				let input = randomizeInput();

				circuit.run(input);

				LogOutput();

				ShowCircuit();
			}

			function qft4() {
				clearLog();

				circuit.init();

				circuit.addGate("h",     0, 0);
				circuit.addGate("cr2",   1, [1, 0]);
				circuit.addGate("cr4",   2, [2, 0]);
				circuit.addGate("cr8",   3, [3, 0]);
				circuit.addGate("h",     4, 1);
				circuit.addGate("cr2",   5, [2, 1]);
				circuit.addGate("cr4",   6, [3, 1]);
				circuit.addGate("h",     7, 2);
				circuit.addGate("cr2",   8, [3, 2]);
				circuit.addGate("h",     9, 3);
				circuit.addGate("swap", 10, [1, 2]);
				circuit.addGate("swap", 11, [0, 3]);
				let input = randomizeInput();

				circuit.run(input);

				LogOutput();

				ShowCircuit();
			}

			function toffoli() {
				clearLog();

				circuit.init();

				circuit.addGate("h",  0, 2);
				circuit.addGate("cs", 1, [1, 2]);
				circuit.addGate("cx", 2, [0, 1]);
				circuit.addGate("cs", 3, [1, 2]);
				circuit.addGate("cs", 4, [1, 2]);
				circuit.addGate("cs", 5, [1, 2]);
				circuit.addGate("cx", 6, [0, 1]);
				circuit.addGate("cs", 7, [0, 2]);
				circuit.addGate("h",  8, 2);

				let input = randomizeInput();

				circuit.run(input);

				LogOutput();

				ShowCircuit();
			}

			function adder() {
				var qasm = "";
				qasm += "// quantum ripple-carry adder from Cuccaro et al, quant-ph/0410184\n";
				qasm += "OPENQASM 2.0;\n";
				qasm += "include \"qelib1.inc\";\n";

				qasm += "gate majority a,b,c\n";
				qasm += "{\n";
				qasm += "  cx c,b;\n";
				qasm += "  cx c,a;\n";
				qasm += "  ccx a,b,c;\n";
				qasm += "}\n";

				qasm += "gate unmaj a,b,c\n";
				qasm += "{\n";
				qasm += "  ccx a,b,c;\n";
				qasm += "  cx c,a;\n";
				qasm += "  cx a,b;\n";
				qasm += "}\n";

				qasm += "qreg cin[1];\n";
				qasm += "qreg a[4];\n";
				qasm += "qreg b[4];\n";
				qasm += "qreg cout[1];\n";
				qasm += "creg ans[5];\n";

				qasm += "// set input states\n";
				qasm += "x a[0]; // a = 0001\n";
				qasm += "x b; // b = 1111\n";

				qasm += "// add a to b, storing result in b\n";
				qasm += "majority cin[0],b[0],a[0];\n";
				qasm += "majority a[0],b[1],a[1];\n";
				qasm += "majority a[1],b[2],a[2];\n";
				qasm += "majority a[2],b[3],a[3];\n";
				qasm += "cx a[3],cout[0];\n";
				qasm += "unmaj a[2],b[3],a[3];\n";
				qasm += "unmaj a[1],b[2],a[2];\n";
				qasm += "unmaj a[0],b[1],a[1];\n";
				qasm += "unmaj cin[0],b[0],a[0];\n";

				qasm += "measure b[0] -> ans[0];\n";
				qasm += "measure b[1] -> ans[1];\n";
				qasm += "measure b[2] -> ans[2];\n";
				qasm += "measure b[3] -> ans[3];\n";
				qasm += "measure cout[0] -> ans[4];\n";

				clearLog();

				circuit.init();

				circuit.importQASM(qasm);

				circuit.run();

				LogOutput();

				ShowCircuit();
			}

			function bigAdder() {
				var qasm = "\n";
				qasm += "// quantum ripple-carry adder\n";
				qasm += "// 8-bit adder made out of 2 4-bit adders from adder.qasm\n";
				qasm += "// Cuccaro et al, quant-ph/0410184\n";
				qasm += "OPENQASM 2.0;\n";
				qasm += "include \"qelib1.inc\";\n";

				qasm += "gate majority a,b,c\n";
				qasm += "{\n";
				qasm += "  cx c,b;\n"; 
				qasm += "  cx c,a;\n"; 
				qasm += "  ccx a,b,c;\n"; 
				qasm += "}\n";
				qasm += "gate unmaj a,b,c\n";
				qasm += "{\n";
				qasm += "  ccx a,b,c;\n";
				qasm += "  cx c,a;\n"; 
				qasm += "  cx a,b;\n"; 
				qasm += "}\n";

				qasm += "// add a to b, storing result in b\n";
				qasm += "gate add4 a0,a1,a2,a3,b0,b1,b2,b3,cin,cout\n";
				qasm += "{\n";
				qasm += "  majority cin,b0,a0;\n";
				qasm += "  majority a0,b1,a1;\n";
				qasm += "  majority a1,b2,a2;\n";
				qasm += "  majority a2,b3,a3;\n";
				qasm += "  cx a3,cout;\n";
				qasm += "  unmaj a2,b3,a3;\n";
				qasm += "  unmaj a1,b2,a2;\n";
				qasm += "  unmaj a0,b1,a1;\n";
				qasm += "  unmaj cin,b0,a0;\n";
				qasm += "}\n";

				qasm += "// add two 8-bit numbers by calling the 4-bit ripple-carry adder\n";
				qasm += "qreg carry[2];\n";
				qasm += "qreg a[8];\n";
				qasm += "qreg b[8];\n";
				qasm += "creg ans[8];\n";
				qasm += "creg carryout[1];\n";
				qasm += "// set input states\n";
				qasm += "x a[0];\n"; // a = 00000001
				qasm += "x b;\n";
				qasm += "x b[6];\n"; // b = 10111111

				qasm += "// output should be 11000000 0\n";
				qasm += "add4 a[0],a[1],a[2],a[3],b[0],b[1],b[2],b[3],carry[0],carry[1];\n";
				qasm += "add4 a[4],a[5],a[6],a[7],b[4],b[5],b[6],b[7],carry[1],carry[0];\n";

				qasm += "measure b[0] -> ans[0];\n";
				qasm += "measure b[1] -> ans[1];\n";
				qasm += "measure b[2] -> ans[2];\n";
				qasm += "measure b[3] -> ans[3];\n";
				qasm += "measure b[4] -> ans[4];\n";
				qasm += "measure b[5] -> ans[5];\n";
				qasm += "measure b[6] -> ans[6];\n";
				qasm += "measure b[7] -> ans[7];\n";
				qasm += "measure carry[0] -> carryout[0];\n";

				clearLog();

				circuit.init();

				circuit.importQASM(qasm);

				circuit.run();

				LogOutput();

				ShowCircuit();
			}

			function clearLog() {
				$("#output").text("");
			}

			function Log(s) {
				$("#output").text($("#output").text() + "\n" + s);
			}

			function randomizeInput() {
				Log("Input:");
				Log("-----");
				input = [];
				for(var i = 0; i < circuit.numQubits; i++) {
					var x = randomInput ? !!Math.round(Math.random()) : 0;
					input.push(x);
					Log(i + ": " + (x ? "|1>" : "|0>"));
				}
				Log("");
				return input;
			}

			function LogOutput() {
				Log("Final state:");
				Log("------------");
				Log(circuit.stateAsString(true));
				Log("");
			}

			function ShowCircuit() {
				var drawing = document.getElementById("drawing");
				drawing.innerHTML = circuit.exportSVG(true);

				var quirkLink = document.getElementById("quirk");
				if(circuit.numQubits <= 16) {
					quirkLink.setAttribute("href", "http://algassert.com/quirk#circuit=" + JSON.stringify(circuit.exportQuirk(true)));

					quirkLink.setAttribute("style", "display: inline");
				} else {
					quirkLink.setAttribute("href", "#");
					quirkLink.setAttribute("style", "display: none");
				}

				Log("Probabilities:");
				Log("--------------");
				Log(circuit.probabilities());
				Log("");

				Log("Measured:");
				Log("---------");
				Log(circuit.measureAll());
				Log("");


				Log("QASM:");
				Log("-----");
				Log(circuit.exportQASM(""));
				Log("");

				Log("QUIL:");
				Log("-----");
				Log(circuit.exportQuil(""));
				Log("");

				Log("pyQuil:");
				Log("-------");
				Log(circuit.exportPyquil(""));
				Log("");

				Log("SVG:");
				Log("----");
				Log(circuit.exportSVG(false));
				Log("");
			}

			$("#bell").click(function () {
				bell();
			});

			$("#toffoli").click(function () {
				toffoli();
			});

			$("#qft2").click(function () {
				qft2();
			});

			$("#qft4").click(function () {
				qft4();
			});

			$("#adder").click(function () {
				adder();
			});

			$("#bigadder").click(function () {
				bigAdder();
			});

			$("#random-input").click(function () {
				randomInput = $(this).is(":checked");
			});

		</script>
	</body>
</html>
